<template>
  <div class="ee-input" :disabled="disabled ? '' : undefined" @click="$refs.input.focus()">
    <div v-if="$slots.before || before" class="before readonly" @click.stop="$emit('beforeClick', $event, this)">
      {{ before }}
      <slot name="before"></slot>
    </div><template v-else />

    <div :class="'textbox' + (readonly ? ' readonly' : '')">
      <span class="icon l" v-if="iconLeft || $slots.left || left" @mousedown.prevent @click="$emit('leftClick', $event, this)">
        <ee-shape v-if="iconLeft" :shape="iconLeft" /><template v-else />
        <span v-if="left" v-html="left"></span><template v-else />
        <slot name="left"></slot>
      </span><template v-else />

      <div v-if="$slots.default" class="input" @mousedown.prevent>
        <slot :i="this"></slot>
        <input ref="input" :tabindex="disabled ? -1 : undefined" v-model="modelValue" :id="name" :name="name" :type="type"
               :disabled="disabled ? 'false' : undefined" :maxlength="maxlength" :readonly="readonly"
               :placeholder="placeholder" @blur="_blur" @focus="_focus" @input="_input" @keydown.esc.prevent="cancel"
               @keydown.enter.prevent="_enter" @click="$emit('inputClick')"
               :style="{ '--ee-input-length': (modelValue || placeholder) ? (modelValue || placeholder).length + 'em' : undefined }" />
      </div>
      <template v-else>
        <input ref="input" :tabindex="disabled ? -1 : undefined" v-model="modelValue" :id="name" :name="name" :type="type"
               :disabled="disabled ? 'false' : undefined" :maxlength="maxlength" :readonly="readonly"
               :placeholder="placeholder" @blur="_blur" @focus="_focus" @input="_input" @keydown.esc.prevent="cancel"
               @keydown.enter.prevent="_enter" @click="$emit('inputClick')" />
      </template>

      <span class="icon r" v-if="iconRight || limit || clear || password || right || $slots.right"
            @mousedown.prevent @click="$emit('rightClick', $event, this)">

        <i v-if="limit" v-show="modelValue || maxlength" class="limit">
          {{ (modelValue?.length || 0) + (maxlength ? "/" + maxlength : "") }}
        </i><template v-else />

        <ee-shape v-if="clear" v-show="modelValue" class="i" shape="close"
                  @click.stop="modelValue = undefined"></ee-shape><template v-else />

        <ee-shape v-if="password" v-show="modelValue" class="i" :on="passwordMode" shape="eye" shape2="eye-close"
                  @click.stop="passwordMode = !passwordMode"></ee-shape><template v-else />

        <span v-if="right" v-html="right"></span><template v-else />
        <ee-shape v-if="iconRight" :shape="iconRight" /><template v-else />
        <slot name="right"></slot>
      </span><template v-else />
    </div>

    <div v-if="$slots.after || after" class="after readonly" @click.stop="$emit('afterClick', $event, this)">
      <slot name="after">
        {{ after }}
      </slot>
    </div><template v-else />
  </div>
</template>

<script type="text/javascript">
import { injectStore } from "ee-vuex";
import enter from "../__mixin/enter";

export default injectStore({
  name: "ee-input",
  mixins: [enter],
  data() {
    return {
      focustext: undefined,
    }
  },
  emits: {
    /** 输入框获得焦点时触发
     * @param {string} value - 文本框输入的值
     * @param {*} i - 组件实例
     */
    onFocus: (value, i) => true,
    /** 输入框失去焦点时触发
     * @param {string} value - 文本框输入的值
     * @param {*} i - 组件实例
     */
    onBlur: (value, i) => true,
    /** 文本框被点击时触发 */
    onInputClick: (i) => true,
    /** modelValue发生变化时，输入框每次输入内容时都会触发
     * @param {string} value - 文本框输入的值
     * @param {*} i - 组件实例
     */
    onValue: (value, i) => true,
    /** 输入框输入完成失去焦点，且文本框内容发生变化时触发
     * 
     * 不触发：输入后按 ESC 键，输入前后内容不变
     * 
     * 触发：输入后按 ENTER 或 TAB 键，点击其它区域
     * @param {string} value - 文本框输入的值
     * @param {*} i - 组件实例
     */
    onChanged: (value, i) => true,
    /** 文本框前方内容点击时
     * @param {MouseEvent} e - 事件参数
     * @param {*} i - 组件实例
     */
    onBeforeClick: (e, i) => true,
    /** 文本框后方内容点击时
     * @param {MouseEvent} e - 事件参数
     * @param {*} i - 组件实例
     */
    onAfterClick: (e, i) => true,
    /** 文本框内左侧内容点击时
     * @param {MouseEvent} e - 事件参数
     * @param {*} i - 组件实例
     */
    onLeftClick: (e, i) => true,
    /** 文本框内右侧内容点击时
     * @param {MouseEvent} e - 事件参数
     * @param {*} i - 组件实例
     */
    onRightClick: (e, i) => true,
  },
  props: {
    /** 输入字符时的操作
     */
    onInput: Function,
    modelValue(value, set) {
      set(value);
      this.$emit("value", value, this);
      if (this.focustext == null)
        this.$emit("changed", value, this)
    },

    // 内部 passwordMode 可能会把 type 设置成 password 所以使用 ee-vuex 的 props
    /** 原生属性，由于兼容性问题，允许的类型有限
     * - @type {('text' | 'password' | 'email' | 'tel' | 'url')}
     */
    type: "text",
    /** 原生属性，提交表单时的字段名，同时会设置 id */
    name: String,
    /** 原生属性，没有文字时展示的提示性文字 */
    placeholder: String,
    /** 原生属性，是否只读，只读会让 tab 不聚焦 */
    readonly: Boolean,
    /** 原生属性，最大输入长度 */
    maxlength: [Number, String],
    /** 原生属性，输入框的输入顺序，-1 则不可聚焦 */
    // tabindex: Number,
    /** 不可聚焦的，tab 键会跳过控件，主要是将 tabindex 设置为 -1，框架不建议自行设置 tabindex  */
    // unfocusable: Boolean,
    /** 原生属性，不可用可以让 tab 键跳过 */
    disabled: Boolean,

    /** 右侧多出 字数 / maxlength，没有maxlength则只显示字数，和其它右侧图标可一起存在，在clear左侧 */
    limit: Boolean,
    /** 右侧多出叉叉图标可以点击清除输入 */
    clear: Boolean,
    /** 右侧多出眼睛图标可以点击展示/隐藏密码 */
    password: Boolean,

    /** 右侧多出图标，值参考ee-icon，图标在默认right插槽内 */
    iconRight: String,
    /** 左侧多出图标，值参考ee-icon，图标在默认left插槽内 */
    iconLeft: String,
    /** 文本框左边内容，例如 https:// ，可以通过 left 插槽自定义 */
    left: String,
    /** 文本框右边内容，例如 .com ，可以通过 right 插槽自定义 */
    right: String,
    /** 文本框前面内容，例如 https:// ，可以通过 before 插槽自定义 */
    before: String,
    /** 文本框后面面内容，例如 .com ，可以通过 after 或 default 插槽自定义 */
    after: String,
  },
  computed: {
    /** 输入框是否为密码模式 */
    passwordMode: {
      get() { return this.type == "password"; },
      set(value) {
        if (value)
          this.type = "password";
        else
          this.type = "text";
      }
    },
    /** 当前输入框是否有焦点 */
    focused: {
      get() { return this.focustext != undefined; },
      set(value) {
        if (value)
          this.$refs.input.focus();
        else
          this.$refs.input.blur();
      }
    }
  },
  methods: {
    _input(e) {
      // console.log("input", e)
      // todo: 通过onInput限制只能输入数字
    },
    focus() {
      console.log("this.ref", this.ref)
      this.ref.focus();
    },
    blur() {
      this.ref.blur();
    },
    _focus() {
      this.focustext = this.modelValue || '';
      this.$emit("focus", this.modelValue, this);
    },
    _blur() {
      if (!this.focustext != !this.modelValue && this.focustext != this.modelValue)
        this.$emit("changed", this.modelValue, this)
      this.focustext = undefined;
      this.$emit("blur", this.modelValue, this);
    },
    cancel() {
      const input = this.$refs.input;
      if (this.focustext == this.modelValue) {
        // 取消选择，如果首次cancel全选了文字并不取消选择，下次点击focus时会有短暂的全选动画
        input.selectionEnd = input.selectionStart;
        input.blur();
      } else {
        this.modelValue = this.focustext;
      }
    },
  },
})
</script>

<style lang="scss">
.ee-input {
  display: inline-flex;
  vertical-align: top;
  background-color: var(--ee-bgcolor);
  width: min(100%, var(--ee-form-input-width));

  .readonly {
    background-color: var(--ee-input-readonly-bg);
    color: var(--ee-input-readonly);
  }

  .before,
  .after {
    border: 1px solid var(--ee-input-border);
    border-radius: var(--ee-border-radius);
    display: flex;
    align-items: center;
    padding: 0.5em 0.75em;
    flex-shrink: 0;
  }

  .before {
    border-right: none;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }

  .after {
    border-left: none;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }

  input::placeholder {
    color: var(--ee-input-placeholder);
  }

  &[disabled] {
    .textbox {
      background-color: var(--ee-input-readonly-bg);
    }
  }

  .textbox {
    border: 1px solid var(--ee-input-border);
    display: flex;
    width: 100%;

    &:hover,
    &:focus-within {
      border-color: var(--ee-input-border-hover);
    }

    &:first-child {
      border-top-left-radius: var(--ee-border-radius);
      border-bottom-left-radius: var(--ee-border-radius);
    }

    &:last-child {
      border-top-right-radius: var(--ee-border-radius);
      border-bottom-right-radius: var(--ee-border-radius);
    }

    .l {
      margin-left: .4em;
      margin-right: -.5em;
    }

    .r {
      margin-right: .4em;
      margin-left: -.5em;
    }

    .icon {
      color: var(--ee-input-icon);
      height: 100%;
      display: flex;

      .limit {
        font-size: .875em;
        font-style: normal;
        user-select: none;
      }

      & > * {
        padding: 0 .3em;
        cursor: inherit;
        display: flex;
        align-items: center;
      }

      .i:hover {
        cursor: pointer;
        color: var(--ee-input-icon-hover);
      }
    }

    .input {
      display: flex;
      align-items: center;
      flex-wrap: wrap;
      padding: 0.5em 0;
      margin: 0 0.75em;
      flex: 1;

      & > input:last-child {
        min-width: min(100%, var(--ee-input-length));
        padding: 0;
      }
    }

    input {
      font-size: 1em;
      color: inherit;
      flex: 1;
      width: 100%;
      padding: 0.5em 0.75em;
      transition: all var(--ee-transition-duration);
      outline: none;
      border: none;
      background-color: transparent;
      line-height: inherit;
      cursor: inherit;
      text-align: inherit;
    }
  }
}

// todo: 下拉选项的样式
.ee-select-options {
  position: absolute;
  display: flex;
  flex-direction: column;
  min-width: 100%;
  border: 1px solid var(--line0);
  background-color: var(--ee-bgcolor);
  box-shadow: var(--ee-shadow);
  padding: 0.25em 0;
  overflow-y: auto;
  top: 100%;
  // todo: 需要制定规范为各种弹窗，fixed层合理分配z-index
  z-index: 1;

  // 超出高度可以上下出滚动条
  // max-height: 100px;
  // todo: 上拉，左拉，右拉，可以通过设置 top, right, bottom, left 简单达成
  // todo: 如果要扩展成导航菜单，应该要能兼容8方向

  // 插入一个小三角标
  &.caret:before {
    content: '';
    width: 0;
    height: 0;
    position: absolute;
    border: var(--ee-bgcolor) solid transparent;
  }

  &.left {
    right: 100%;
    top: 0;

    &.caret:before {}
  }

  &.up.left,
  &.down.left {
    right: 0;
  }

  &.right {
    left: 100%;
    top: 0;

    &.caret:before {}
  }

  &.up.right,
  &.down.right {
    left: 0;
  }

  &.down {
    top: 100%;

    &.caret:before {}
  }

  &.up {
    bottom: 100%;
    top: unset;

    &.caret:before {}
  }
}
</style>